/*!
 * vue-easy-loader v1.0.0
 * @author yandong
 *
 * https://github.com/ereddate/vue-easy-loader
 */
"use strict";
(win => {
  let doc = win.document,
    hasOwn = {}.hasOwnProperty,
    _instanceOf = _constructor => {
      return function(o) {
        return o instanceof _constructor;
      };
    },
    isFunction = function(obj) {
      return typeof obj === "function" && typeof obj.nodeType !== "number";
    },
    isEmptyObject = function(obj) {
      for (var name in obj) {
        return false;
      }
      return true;
    },
    isPlainObject = function(obj) {
      var key;
      if (!obj || typeof obj !== "object" || obj.nodeType) {
        return false;
      }
      try {
        if (
          obj.constructor &&
          !hasOwn.call(obj, "constructor") &&
          !hasOwn.call(obj.constructor.prototype, "isPrototypeOf")
        ) {
          return false;
        }
      } catch (e) {
        return false;
      }
      for (key in obj) {
        break;
      }
      return key === undefined || hasOwn.call(obj, key);
    },
    extend = function(a, b) {
      a = a || {};
      for (let i in b) {
        if (a[i] && isPlainObject(a[i])) {
          extend(a[i], b[i]);
        } else {
          a[i] = b[i];
        }
      }
      return a;
    },
    ready = function(callback) {
      var then = this,
        completed = () => {
          doc.removeEventListener("DOMContentLoaded", completed);
          win.removeEventListener("load", completed);
          isFunction(callback) && callback();
        };
      doc.addEventListener("DOMContentLoaded", completed);
      win.addEventListener("load", completed);
      return then;
    };

  String.prototype._firstUpper = function() {
    return this.substr(0, 1).toUpperCase() + this.substr(1, this.length - 1);
  };

  class mod {
    constructor() {
      this.sets = {};
      this.amd = {};

      return this;
    }
    defaultFontSize(num) {
      if (!num) {
        document.getElementsByTagName("html")[0].style.fontSize = "";
        return;
      }
      // eslint-disable-next-line no-redeclare
      num = num || 16;
      let iWidth = (document.documentElement || document.body).clientWidth,
        iHeight = (document.documentElement || document.body).clientHeight,
        fontSize =
          (window.orientation &&
            (window.orientation === 90 || window.orientation === -90)) ||
          iHeight < iWidth
            ? iHeight / num
            : iWidth / num;
      window.baseFontSize = fontSize;
      document.getElementsByTagName("html")[0].style.fontSize =
        fontSize.toFixed(2) + "px";
      return fontSize;
    }
    isFunction(obj) {
      return isFunction(obj);
    }
    isEmptyObject(obj) {
      return isEmptyObject(obj);
    }
    isPromise(obj) {
      return (
        typeof obj === "object" &&
        obj.then &&
        this.isFunction(obj.then) &&
        obj instanceof Promise
      );
    }
    createObject(obj, name, value, callback) {
      (typeof Reflect !== "undefined" && Reflect.defineProperty
        ? Reflect.defineProperty
        : Object.defineProperty)(obj, name, {
        get() {
          return value;
        },
        set(newValue) {
          if (value === newValue) return;
          var oldValue = value;
          value = newValue;
          callback && callback(newValue, oldValue);
        }
      });
      return this;
    }
    isPlainObject(obj) {
      return isPlainObject(obj);
    }
    extend(a, b) {
      return extend(a, b);
    }
    isArray(obj) {
      return (
        (Array.isArray || _instanceOf(Array))(obj) && typeof obj !== "string"
      );
    }
    each(a, b, c) {
      var d,
        e = 0,
        g = this.isArray(a),
        f = (a && a.length) || 0;
      if (c) {
        if (g) {
          for (; f > e; e++) if (((d = b.apply(a[e], c)), d === !1)) break;
        } else {
          for (let e in a) if (((d = b.apply(a[e], c)), d === !1)) break;
        }
      } else if (g) {
        for (; f > e; e++) if (((d = b.call(a[e], e, a[e])), d === !1)) break;
      } else
        for (let e in a) if (((d = b.call(a[e], e, a[e])), d === !1)) break;
      return a;
    }
  }

  class Use {
    constructor() {
      this.callback = next => {
        next();
      };
      return this;
    }
    get(item, that, resolve, reject, options) {
      let url = "";
      if (that.sets && that.sets.alias[item]) {
        if (/^http[s]/.test(that.sets.alias[item])) {
          url = that.sets.alias[item];
        } else if (/\.vue/.test(that.sets.alias[item])) {
          return new Ajax().get(
            item,
            that.sets.base + that.sets.alias[item],
            that,
            resolve,
            reject
          );
        } else {
          url = that.sets.base + that.sets.alias[item];
        }
      } else if (/^http[s]/.test(item)) {
        url = item;
      } else {
        that.amd[item] && (that.amd[item].status = "error");
        reject("[" + item + "] Illegal document addresses.");
        return;
      }
      if (url !== "") {
        let head = document.getElementsByTagName("head")[0],
          fileType = /\.css/.test(that.sets.alias[item])
            ? "css"
            : /png|gif|jpg/.test(that.sets.alias[item])
            ? "img"
            : "js",
          script = document.createElement(
            fileType === "js" ? "script" : fileType === "css" ? "link" : "img"
          );
        script[fileType === "css" ? "href" : "src"] =
          url + "?t=" + (Math.random(1000) + "").replace(/\./gim, "");
        if (fileType === "css") {
          script.rel = "stylesheet";
        }
        script.timeout = setTimeout(() => {
          script.onload = null;
          script.onerror({
            message: "[" + item + "] timeout."
          });
        }, (options && options.timeout) || 3000);
        head.appendChild(script);
        script.onload = () => {
          script.timeout && clearTimeout(script.timeout);
          that.amd[item].status = "loaded";
          this.callback(() => {
            resolve(that.amd);
          });
        };
        script.onerror = err => {
          that.amd[item].status = "error";
          this.callback(() => {
            reject(err);
          });
        };
      } else {
        that.amd[item] && (that.amd[item].status = "error");
        reject("[" + item + "] Illegal document addresses.");
      }
      return this;
    }
  }

  class Ajax {
    constructor() {
      this.callback = next => {
        next();
      };
      return this;
    }
    get(name, url, that, resolve, reject) {
      let self = this;
      easy.use("less axios", () => {
        if (window.axios) {
          that.amd["axios"].exports = {
            axios: window.axios
          };
          that.amd["axios"].status = "loaded";
        }
        window.axios
          ? window.axios
              .get(url)
              .then(res => {
                if (/\.vue/.test(url)) {
                  let a = document.createElement("base");
                  a.innerHTML = res.data;
                  let template = a.children[0].innerHTML,
                    js = a.children[1].innerHTML,
                    style = a.children[2].innerHTML;
                  let obj =
                    js
                      .replace(/(export\s+default\s+{)/gim, (a, b) => {
                        a = a.replace(
                          b,
                          'Vue.component("' +
                            name +
                            '", {template:"' +
                            template
                              .replace(/"/gim, '\\"')
                              .replace(/'/gim, "\\'")
                              .replace(/\r|\n/gim, "")
                              .replace(/\s{2,}/gim, " ") +
                            '",'
                        );
                        return a;
                      })
                      .replace(/;$/gim, "") + ")";
                  obj =
                    "return new Promise((resolve, reject) => { resolve(" +
                    obj +
                    ");});";
                  obj = new Function(obj)();
                  that.amd[name].exports = {
                    component: obj,
                    getStyle: function() {
                      /* easy
                      .set({
                        alias: {
                          less:
                            "https://cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js"
                        }
                      })
                      .use("less", () => { */
                      if (window.less) {
                        that.amd["less"].exports = {
                          less: window.less
                        };
                        that.amd["less"].status = "loaded";
                        let head = document.getElementsByTagName("head")[0];
                        let styles = document.createElement("style");
                        styles.id = name;
                        head.appendChild(styles);
                        window.less.render(style, {}, function(error, output) {
                          if (error) {
                            console.log(error);
                            return;
                          }
                          styles.innerHTML = output.css;
                        });
                      }
                      //});
                    }
                  };
                } else if (/\.less/.test(url)) {
                  let style = res.data;
                  that.amd[name].exports = {
                    component: null,
                    getStyle: function() {
                      /*  easy
                      .set({
                        alias: {
                          less:
                            "https://cdnjs.cloudflare.com/ajax/libs/less.js/3.11.1/less.min.js"
                        }
                      })
                      .use("less", () => { */
                      if (window.less) {
                        that.amd["less"].exports = {
                          less: window.less
                        };
                        that.amd["less"].status = "loaded";
                        let head = document.getElementsByTagName("head")[0];
                        let styles = document.createElement("style");
                        styles.id = name;
                        head.appendChild(styles);
                        window.less.render(style, {}, function(error, output) {
                          if (error) {
                            console.log(error);
                            return;
                          }
                          styles.innerHTML = output.css;
                        });
                      }
                      //});
                    }
                  };
                }
                that.amd[name].status = "loaded";
                self.callback(() => {
                  resolve(that.amd);
                });
              })
              .catch(err => {
                that.amd[name].status = "error";
                self.callback(() => {
                  reject(err);
                });
              })
          : reject({
              message: "window.axios loading error."
            });
        //console.log(url, resolve, reject);
      });
      return this;
    }
  }

  Promise.prototype.delay = function(time) {
    let that = this;
    return this.then(res => {
      // eslint-disable-next-line no-unused-vars
      return new Promise((resolve, reject) => {
        that.promiseTimeout && clearTimeout(that.promiseTimeout);
        that.promiseTimeout = setTimeout(
          () => {
            resolve(res);
          },
          time ? time * 1000 : 1000
        );
      });
    });
  };

  class Easy extends mod {
    constructor() {
      super();
      this.DOM = {};
      return this;
    }
    set(v) {
      this.extend(this.sets, v);
      return this;
    }
    use(depend, callback) {
      const that = this;
      if (typeof depend === "string") {
        depend = depend.split(" ");
      }
      new Promise((resolve, reject) => {
        let promises = [];
        for (let i = 0; i < depend.length; i++) {
          let item = depend[i];
          if (that.amd[item]) continue;
          that.amd[item] = {
            name: item,
            status: "init",
            exports: {}
          };
          promises.push(
            new Promise((resolve, reject) => {
              if (
                that.sets &&
                that.sets.alias[item] &&
                /\.vue|\.less/.test(that.sets.alias[item])
              ) {
                let use = new Ajax().get(
                  item,
                  that.sets.base + that.sets.alias[item],
                  that,
                  resolve,
                  reject
                );
                use.callback = next => {
                  next();
                };
              } else {
                let use = new Use().get(item, that, resolve, reject, {
                  timeout: 5000
                });
                use.callback = next => {
                  next();
                };
              }
            })
          );
        }
        if (promises.length > 0) {
          Promise.all(promises)
            .then(function() {
              resolve.apply(this, arguments);
            })
            .catch(function() {
              reject.apply(this, arguments);
            });
        } else {
          resolve();
        }
      })
        .then(function() {
          callback && callback.call(this);
        })
        .catch(function(err) {
          callback && callback.call(this, err);
        });
      return this;
    }
    ready(callback) {
      ready(callback);
      return this;
    }
  }

  let easy = new Easy();

  win.Easy = easy;

  let define = function(dependName, depends, callback) {
    let args = arguments,
      len = args.length;
    if (len === 1) {
      if (easy.isFunction(dependName)) {
        callback = dependName;
        dependName = null;
        depends = null;
      } else if (typeof dependName === "string") {
        callback = null;
        depends = null;
      }
    } else if (len === 2) {
      if (easy.isArray(dependName)) {
        callback = depends;
        depends = dependName;
      } else if (easy.isFunction(depends)) {
        callback = depends;
      }
    } else if (len === 3) {
      if (typeof depends === "string") depends = depends.split(" ");
    }
    let fn = () => {
      callback &&
        callback(
          name => {
            return (
              easy.amd[name] &&
              !isEmptyObject(easy.amd[name].exports) &&
              easy.amd[name].exports
            );
          },
          (dependName &&
            easy.amd[dependName] &&
            easy.amd[dependName].exports) ||
            {},
          (dependName &&
            easy.amd[dependName] &&
            easy.amd[dependName].exports) ||
            {}
        );
    };
    if (easy.isArray(depends)) {
      easy.use(depends, () => {
        fn();
      });
    } else {
      fn();
    }
  };
  win.define = define;
  define(() => {
    let main = document.getElementById("easyroot");
    if (main) {
      easy.ready(() => {
        let name = main.getAttribute("data-main");
        name && easy.use(name);
      });
    }
  });
})(window);
